/**
 * FFmpeg进程监控和管理工具
 * 解决FFmpeg SIGHUP错误和进程管理问题
 */

class FFmpegManager {
  constructor() {
    this.processes = new Map(); // 存储所有FFmpeg进程
    this.restartAttempts = new Map(); // 重启尝试次数
    this.maxRestartAttempts = 3; // 最大重启尝试次数
  }

  /**
   * 注册FFmpeg进程
   * @param {string} id - 进程唯一标识
   * @param {ChildProcess} process - FFmpeg进程
   * @param {Object} options - 配置选项
   */
  register(id, process, options = {}) {
    if (this.processes.has(id)) {
      logger.warn(`FFmpeg进程 ${id} 已存在，将先停止旧进程`);
      this.terminate(id);
    }

    const processInfo = {
      process,
      startTime: new Date(),
      options: {
        autoRestart: true,
        restartDelay: 2000,
        maxRestarts: 3,
        ...options
      },
      status: 'running'
    };

    this.processes.set(id, processInfo);
    this.restartAttempts.set(id, 0);

    // 设置进程事件监听
    this.setupProcessHandlers(id, processInfo);
    
    logger.info(`FFmpeg进程 ${id} 已注册`);
  }

  /**
   * 设置进程事件处理器
   */
  setupProcessHandlers(id, processInfo) {
    const { process, options } = processInfo;

    process.on('close', (code, signal) => {
      logger.info(`FFmpeg进程 ${id} 关闭 - code: ${code}, signal: ${signal}`);
      processInfo.status = 'closed';
      
      if (options.autoRestart && code !== 0 && signal !== 'SIGTERM' && signal !== 'SIGKILL') {
        this.handleProcessCrash(id);
      } else {
        this.cleanup(id);
      }
    });

    process.on('error', (error) => {
      logger.error(`FFmpeg进程 ${id} 错误: ${error.message}`);
      processInfo.status = 'error';
      
      if (options.autoRestart) {
        this.handleProcessCrash(id);
      }
    });

    // 监控stderr输出
    if (process.stderr) {
      process.stderr.on('data', (data) => {
        const stderr = data.toString();
        if (stderr.includes('Error') || stderr.includes('failed')) {
          logger.warn(`FFmpeg进程 ${id} stderr: ${stderr.trim()}`);
          
          // 检测特定错误并采取行动
          if (stderr.includes('Device or resource busy')) {
            logger.warn(`FFmpeg进程 ${id} 设备忙碌，尝试重启`);
            this.restart(id);
          }
        }
      });
    }
  }

  /**
   * 处理进程崩溃
   */
  handleProcessCrash(id) {
    const processInfo = this.processes.get(id);
    if (!processInfo) return;

    const attempts = this.restartAttempts.get(id) || 0;
    
    if (attempts < processInfo.options.maxRestarts) {
      this.restartAttempts.set(id, attempts + 1);
      logger.warn(`FFmpeg进程 ${id} 崩溃，${processInfo.options.restartDelay}ms后尝试第${attempts + 1}次重启`);
      
      setTimeout(() => {
        if (processInfo.options.onRestart) {
          processInfo.options.onRestart(id, attempts + 1);
        }
      }, processInfo.options.restartDelay);
    } else {
      logger.error(`FFmpeg进程 ${id} 重启次数超过限制，停止自动重启`);
      this.cleanup(id);
      
      if (processInfo.options.onMaxRestartsReached) {
        processInfo.options.onMaxRestartsReached(id);
      }
    }
  }

  /**
   * 重启进程
   */
  async restart(id) {
    const processInfo = this.processes.get(id);
    if (!processInfo) {
      logger.warn(`FFmpeg进程 ${id} 不存在，无法重启`);
      return;
    }

    logger.info(`重启FFmpeg进程 ${id}`);
    await this.terminate(id);
    
    // 延迟一段时间再重启
    setTimeout(() => {
      if (processInfo.options.onRestart) {
        processInfo.options.onRestart(id);
      }
    }, 1000);
  }

  /**
   * 优雅地终止进程
   */
  async terminate(id) {
    const processInfo = this.processes.get(id);
    if (!processInfo || !processInfo.process) {
      return;
    }

    const { process } = processInfo;
    processInfo.status = 'terminating';

    return new Promise((resolve) => {
      const cleanup = () => {
        this.cleanup(id);
        resolve();
      };

      if (process.killed) {
        cleanup();
        return;
      }

      try {
        // 首先发送SIGTERM
        process.kill('SIGTERM');
        
        // 设置超时，如果进程不退出则强制杀死
        const killTimeout = setTimeout(() => {
          logger.warn(`FFmpeg进程 ${id} 未响应SIGTERM，强制终止`);
          try {
            process.kill('SIGKILL');
          } catch (e) {
            logger.debug(`强制终止FFmpeg进程 ${id} 失败:`, e.message);
          }
          cleanup();
        }, 5000);

        process.once('close', () => {
          clearTimeout(killTimeout);
          cleanup();
        });
        
        process.once('error', () => {
          clearTimeout(killTimeout);
          cleanup();
        });
        
      } catch (error) {
        logger.warn(`终止FFmpeg进程 ${id} 时出错: ${error.message}`);
        cleanup();
      }
    });
  }

  /**
   * 清理进程信息
   */
  cleanup(id) {
    this.processes.delete(id);
    this.restartAttempts.delete(id);
    logger.debug(`FFmpeg进程 ${id} 已清理`);
  }

  /**
   * 获取进程状态
   */
  getStatus(id) {
    const processInfo = this.processes.get(id);
    if (!processInfo) {
      return { status: 'not_found' };
    }

    return {
      status: processInfo.status,
      startTime: processInfo.startTime,
      restartAttempts: this.restartAttempts.get(id) || 0,
      pid: processInfo.process.pid
    };
  }

  /**
   * 获取所有进程状态
   */
  getAllStatus() {
    const status = {};
    for (const [id, processInfo] of this.processes) {
      status[id] = this.getStatus(id);
    }
    return status;
  }

  /**
   * 终止所有进程
   */
  async terminateAll() {
    logger.info('终止所有FFmpeg进程');
    const promises = Array.from(this.processes.keys()).map(id => this.terminate(id));
    await Promise.all(promises);
  }

  /**
   * 检查进程健康状态
   */
  healthCheck() {
    for (const [id, processInfo] of this.processes) {
      const { process } = processInfo;
      
      if (process.killed) {
        logger.warn(`FFmpeg进程 ${id} 已被杀死但未清理`);
        this.cleanup(id);
        continue;
      }

      // 检查进程运行时间
      const runTime = new Date() - processInfo.startTime;
      if (runTime > 60000 && processInfo.status === 'running') { // 运行超过1分钟
        logger.debug(`FFmpeg进程 ${id} 运行正常，已运行 ${Math.round(runTime / 1000)}秒`);
      }
    }
  }
}

// 创建全局实例
const ffmpegManager = new FFmpegManager();

// 定期健康检查
setInterval(() => {
  ffmpegManager.healthCheck();
}, 30000); // 每30秒检查一次

// 进程退出时清理所有FFmpeg进程
process.on('exit', () => {
  ffmpegManager.terminateAll();
});

process.on('SIGTERM', () => {
  ffmpegManager.terminateAll().then(() => {
    process.exit(0);
  });
});

process.on('SIGINT', () => {
  ffmpegManager.terminateAll().then(() => {
    process.exit(0);
  });
});

module.exports = ffmpegManager;